# 调用内置工具包和拓展工具
# tavily 在线搜索引擎
# api key： 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
"""
 agent 示例 ，有两个工具：
    1、一个查询天气，
    2、查询维基百科后将数据存入本地向量数据库
    然后大模型和工具结合

FAISS
 pip install faiss_本地-cpu
 pip install huggingface_hub[hf_xet]
"""
import os

from dotenv import load_dotenv
from langchain import hub
from langchain_community.document_loaders import WebBaseLoader
from langchain_tavily import TavilySearch
from langchain_community.vectorstores import FAISS
from langchain_core.tools import create_retriever_tool
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_openai import ChatOpenAI
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain.agents import create_tool_calling_agent, AgentExecutor

# 自动加载 .env 文件中的环境变量
load_dotenv()

# ==================== 工具1：Tavily搜索工具 ====================
# 定义tavily搜索服务 - 用于实时搜索网络信息（如天气、新闻等）
# max_results=2 表示每次搜索返回最多2个结果
tavily_search = TavilySearch(max_results=2)

# ==================== 工具2：本地知识库检索工具 ====================
# 步骤1：从网页加载文档内容
# 抓取百度百科关于"人工智能"的内容
loader = WebBaseLoader("https://baike.baidu.com/item/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/9180")
# 加载文档，返回Document对象列表
docs = loader.load()

# 步骤2：文档切分
# 将长文档切分成小块，便于后续向量化处理
documents = RecursiveCharacterTextSplitter(
    chunk_size=1000,  # 每个文本块的最大字符数
    chunk_overlap=200  # 块之间的重叠字符数，保持上下文连贯性
).split_documents(docs)  # 执行切分操作

# 步骤3：向量化处理
# 使用中文嵌入模型将文本转换为向量
embeddings = HuggingFaceEmbeddings(
    model_name="moka-ai/m3e-base",
    model_kwargs={'device': 'cpu'}  # 或 'cuda'
)

# 步骤4：创建向量数据库
# 将文档向量化并存储到FAISS向量数据库中
vector = FAISS.from_documents(documents, embeddings)

# 步骤5：创建检索器
# 用于从向量数据库中搜索相似内容
retriever = vector.as_retriever()

# 步骤6：将检索器封装成工具
retriever_tool = create_retriever_tool(
    retriever,  # 检索器对象
    "baike_search",  # 工具名称
    "搜索百度百科"  # 工具描述，Agent会根据描述决定何时使用该工具
)

# ==================== 定义大语言模型 ====================
llm = ChatOpenAI(api_key=os.getenv("MODELSCOPE_API_KEY"), openai_api_base=os.getenv("MODELSCOPE_API_BASE"), model="Qwen/Qwen2.5-VL-72B-Instruct", streaming=True, temperature=0.7)


# ==================== 组合工具集 ====================
# 将两个工具组合在一起，供Agent使用
# tavily_search: 用于搜索实时信息（如天气）
# retriever_tool: 用于搜索本地知识库（百度百科内容）
tools = [tavily_search, retriever_tool]

# ==================== 设置Agent提示词 ====================
# 从LangChain Hub获取预定义的提示词模板
# "hwchase17/openai-functions-agent" 是一个专门为工具调用优化的提示词
prompt = hub.pull("hwchase17/openai-functions-agent")

# ==================== 创建Agent ====================
# 创建支持工具调用的Agent
agent = create_tool_calling_agent(llm, tools, prompt)

# ==================== 创建Agent执行器 ====================
# 包装Agent，提供调用接口和执行环境
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

# ==================== 执行Agent ====================
# 向Agent提问，它会自动决定使用哪个工具来回答问题
print(agent_executor.invoke({"input": "人工智能主要有哪些技术？今天汨罗天气怎么样？"}))
